package com.squeekeek.util.qrcode.Core;

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Size;

public class OpenCVExtras {
	public static final String OP_LT = "lessthan";
	public static final String OP_GT = "greatthan";
	public static final String OP_EQ = "equal";
	
	public static Mat subtractPoints2D(Point p1, Point p2) {
		Mat diff = new Mat(2, 1, CvType.CV_32FC1);
		
		diff.put(0, 0, p1.x - p2.x);
		diff.put(1, 0, p1.y - p2.y);
		
		return diff;
	}
	
	public static Mat pointToMat3D(Point p) {
		Mat ans = new Mat(3, 1, CvType.CV_64FC1);
		
		ans.put(0, 0, p.x);
		ans.put(1, 0, p.y);
		ans.put(2, 0, 1.0);
		
		return ans;
	}
	
	public static Point mat3DToPoint(Mat m) {
		Point ans;
		
		if(m.size().equals(new Size(3, 1))) {
			return null;
		}
		
		ans = new Point(m.get(0, 0)[0], m.get(1, 0)[0]);
		
		return ans;
	}
	
	public static double detVectors2D(Mat vec1, Mat vec2) {
		return vec1.get(0, 0)[0] * vec2.get(1, 0)[0] - vec2.get(0, 0)[0] * vec2.get(1, 0)[0];
	}
	
	public static Mat lawOfCosines(List <Point> points) {
		Mat sideAngleMat = new Mat(3, 2, CvType.CV_32FC1);
		double sideLen[] = new double[3];
		
		if(points.size() != 3) {
			return null;
		}
		
		for(int i = 0; i < 3; i++) {
			sideLen[i] = Core.norm(subtractPoints2D(points.get(i), points.get((i + 1) % 3)));
			sideAngleMat.put(i, 0, sideLen[i]);
		}
		
		for(int i = 0; i < 3; i++) {
			sideAngleMat.put((i + 2) % 3, 1, Math.toDegrees(Math.acos(-(sideLen[(i + 2) % 3] * sideLen[(i + 2) % 3] - sideLen[i] * sideLen[i] - sideLen[(i + 1) % 3] * sideLen[(i + 1) % 3]) / (2 * sideLen[i] * sideLen[(i + 1) % 3]))));
		}
		
		return sideAngleMat;
	}
	
	public static Mat lawOfCosines(Point p1, Point p2, Point p3) {
		List <Point> points = new ArrayList <Point> ();
		
		points.add(p1);
		points.add(p2);
		points.add(p3);
		
		return lawOfCosines(points);
	}
	
	public static boolean compDouble(double a, double b, String op, int tolerance) {
		if(op.equals(OP_LT)) {
			return (int) (tolerance * a) < (int) (tolerance * b);
		}
		else if(op.equals(OP_GT)) {
			return (int) (tolerance * a) > (int) (tolerance * b);
		}
		else if(op.equals(OP_EQ)) {
			return (int) (tolerance * a) == (int) (tolerance * b);
		}
		
		return false;
	}
}
